﻿#import os
#import sys




# Настройка вывода ошибок в файл

# Определяется текущая директория

#__dir__ = os.path.dirname(os.path.abspath(__file__))
#path_error = os.path.join(__dir__, "so_test_error.log")

# Вывод ошибок перенаправляется в файл error.log в текущей директории

#sys.stderr = open(path_error, 'a')

from os import path
from db import base as superbase
from db import table as supertable
from db import atable as superatable
import pypyodbc



class base(superbase):
	"This class is an odbc connector"
	#print (self.__doc__)
	#beginning of class suite
	def __init__(self):
		super(base, self).__init__()
		self.driver=pypyodbc
		self.dsn='files'
		self.netdrive='V:'
	
	def open(self):
		"This function opens connection to db"
		#print (self.open.__doc__)
		#beginning of function suite
		self.conn = self.driver.connect(dsn=self.dsn)
		self.cursor = self.conn.cursor()
		return
		
	def execute_in_cycle(self, string, row=None):
		"This function executes statement against base optional for row of values"
		#beginning of function suite
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		self.conn.commit()
		#end of function suite
		#Функция ничего не возвращает
		return
	
	def execute_many_in_cycle(self, string, rows):
		"This function executes a statement for rows of values"
		#beginning of function suite
		#Выполняется запрос в зависимости от наличия аргументов
		self.cursor.executemany(string, rows)
		self.conn.commit()
		#end of function suite
		#Функция возвращает результат запроса
		return

	def fetch_in_cycle(self, string, row=None, lim=0):
		"This function fetches a statement optional for row of values"
		#beginning of function suite
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		if lim==0:
			result=self.cursor.fetchall()
		else:
			result=self.cursor.fetchmany(lim)
		return result
		#end of function suite
		#Функция возвращает результат запроса

	def commit_in_cycle(self, string):
		"This function executes statement against base and commits it"
		#beginning of function suite
		#end of function suite
		return self.execute_in_cycle(string)

	def execute(self, string, row=None):
		"This function connects to base and executes a statement optional for row of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		self.conn.commit()
		#Выполняется отключение от базы данных
		self.disconnect()
		#end of function suite
		#Функция ничего не возвращает
		return

	def execute_many(self, string, rows):
		"This function connects to base and executes a statement for rows of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		self.cursor.executemany(string, rows)
		self.conn.commit()
		#Выполняется отключение от базы данных
		self.disconnect()
		#end of function suite
		#Функция возвращает результат запроса
		return
		
	def fetch(self, string, row=None, lim=0):
		"This function connects to base and fetches a statement optional for row of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		if lim==0:
			result=self.cursor.fetchall()
		else:
			result=self.cursor.fetchmany(lim)
		self.disconnect()
		return result
		#end of function suite
		#Функция возвращает результат запроса

	def generate(self, string, row=None, lim=1000):
		"This function connects to base and fetches a statement optional for row of values"
		#beginning of function suite
		#Выполняется подключение к базе данных
		self.connect()
		#Выполняется запрос в зависимости от наличия аргументов
		if not row:
			self.cursor.execute(string)
		else:
			self.cursor.execute(string, [row])
		while True:
			results=self.cursor.fetchmany(lim)
			if results==[]: 
				self.disconnect()
				break
			for result in results:
				yield result
		#end of function suite
		#Функция возвращает генератор результатов запроса
	
	def iterate(self, string, row=None, start=None, stop=None, step=None):
		"This function connects to base and executes a statement optional for a row of values"
		#beginning of function suite
		#end of function suite
		#Функция возвращает итератор результатов запроса
		return islice(self.generate(string, row), start, stop, step)

	def commit(self, string):
		"This function connects to base, executes a statement and commits it"
		#beginning of function suite
		#end of function suite
		return self.execute(string)

	#end of class base suite

class relations:
	"This class counts and select records for relations"
	#beginning of class suite
	#print (relations.__doc__)
	#Инициализация:
	def __init__(self):
		self.log=None
		self.base=base()
	
	def SelectTables(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if name==table[2].decode('utf-8') and table[3].decode('utf-8')=='TABLE':
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def SelectlikeTables(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if name in table[2].decode('utf-8') and table[3].decode('utf-8')=='TABLE':
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def SelectAny(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if name==table[2].decode('utf-8'):
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def SelectlikeAny(self, names=[]):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		self.base.connect()
		self.base.cursor.tables()
		tables=self.base.cursor.fetchall()
		self.base.disconnect()
		if names==[]:
			result=tables
		else:
			result=[]
			for name in names:
				for table in tables:
					if name in table[2].decode('utf-8'):
						result+=[table]
		#end of function suite
		#Функция возвращает список таблиц в каталоге
		return result

	def CountTables(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectTables(names))
	
	def CountlikeTables(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectlikeTables(names))

	def CountAny(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectAny(names))
	
	def CountlikeAny(self, names=[]):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц в каталоге
		return len(self.SelectlikeAny(names))

	#end of class relations suite

class table(supertable):
	"This class is a manipulater for views"
	#beginning of class suite
	#print (self.__doc__)
	#Инициализация:
	def __init__(self):
		super(table, self).__init__()
		self.seq=False
		self.case=False
		self.base=base()
		self.relations=relations()
		self.relations.base=self.base
	
	def SqlCreateTab(self, param, name, fields, primary, comment):
		"Function returns sql string for the view create query"
		result='CREATE'+' '+param+' '+'TABLE'+' '+path.abspath(self.base.netdrive)+self.SqlCase(name)+' '+self.newline
		result+='('+self.newline
		for row in fields:
			result+=self.SqlCase(row[0])+' '+self.SqlCase(row[1])+' '+self.SqlCase(row[2])+','+self.newline
		if primary!='':
			result+='CONSTRAINT'+' '+self.SqlCase(name)+self.constraint_postfix+' '+'PRIMARY KEY ('+self.SqlCase(primary)+')'
		else:
			result=result[:-2]
		result+=self.newline+')'
		result+=self.tab_create_extra(name, comment)
		return result

	def SqlDropTab(self, name):
		"Function returns sql string for the table drop query"
		return 'DROP TABLE'+' '+path.abspath(self.base.netdrive)+self.SqlCase(name)+' '+self.tab_drop_extra()

	#end of class table suite

class atable(superatable):
	"This class is a manipulator for a table"
	#beginning of class suite
	#print (self.__doc__)
	def __init__(self):
		super(atable, self).__init__()
		self.table=table()

	#end of class atable suite

#Вывод ошибок возвращается "в исходное положение"

#sys.stderr.close()
#sys.stderr = sys.__stderr__